
#ifndef _CPP_INTEGRATION_KERNEL_CU_
#define _CPP_INTEGRATION_KERNEL_CU_


#include "GPU_device_functions.cu"
#include "RandomNumberGenerator.cu"
#include "Cuda_Config.h"
__global__ void calculateFirstFitness(float *individuals, ANNDATA *trainData, int trainDatasize, float* fitnessVector){


	int blockId		= blockIdx.x;
	int threadId	= threadIdx.x;
	int index = blockId * blockDim.x + threadId;

	Chrosomome individual = &individuals[CONNECTION_NUM * index];

	float result[OUTPUT_NUM];
	float err = 0.0f;
	for(int i = 0 ; i < trainDatasize ; i++) {
		/*float* result = feedForward(annCnfg,individual,trainData[i].input);*/
		feedForward(individual,trainData[i].input,&result[0]);
		err += getANNerror(result,trainData[i].output);
	}	
		fitnessVector[index]= err;
}



__global__ void evolvePopulation(float* individuals,ANNDATA *training_data, int trainDataSize, Rand48 *random, float *fitnessVector, Chrosomome res, float* minFitness){

	int blockId		= blockIdx.x;
	int threadId	= threadIdx.x;
	int index = blockId * blockDim.x + threadId;

   extern  __shared__ ANNData data[];
	__shared__ float s_fitVec[BLOCK_SIZE];
	//cache trainig data to shared memory
	
	if(threadId == 0){
		for(int i = 0 ; i < trainDataSize ; i++)
			data[i] = training_data[i];
	}

	__syncthreads();

	s_fitVec[threadId] = fitnessVector[index];
	__syncthreads();

	Chrosomome individual = &individuals[CONNECTION_NUM * index];

	//Chrosomome individual = (float*)((char*)individuals + index * pitch);

	////choose 3 other individuals for mutation
	rand48_loadState(*random);
	int r0 = rand48_nextInt(*random) % MAX_POPULATION;
	int r1 = rand48_nextInt(*random) % MAX_POPULATION;
	int r2 = rand48_nextInt(*random) % MAX_POPULATION;
	

	float* r_0 = &individuals[r0 * CONNECTION_NUM];
	float* r_1 = &individuals[r1 * CONNECTION_NUM];
	float* r_2 = &individuals[r2 * CONNECTION_NUM];

	float mutatedVec[CONNECTION_NUM];
	mutate(r_0, r_1, r_2,mutatedVec);
	
	float randomNumbers[CONNECTION_NUM];
	for(int i = 0 ; i < CONNECTION_NUM ; i++){
		randomNumbers[i] = rand48_nextFloat(*random);
	}
	
	rand48_storeState(*random);


	float crossVec[CONNECTION_NUM];
	crossover(individual, mutatedVec,randomNumbers,crossVec);

	//test if crossVec reduce the 
 
	float result[OUTPUT_NUM];
	float err = 0.0f;
	for(int i = 0 ; i < trainDataSize ; i++){ 
		/*float* result = feedForward(annConfig,crossVec,training_data[i].input);*/
		feedForward(crossVec,data[i].input,result);
		err += getANNerror(result,data[i].output);
	}
	//__syncthreads();

	
	if(err < s_fitVec[threadId]){
		s_fitVec[threadId] = err;
		for(int indx = 0  ; indx < CONNECTION_NUM ; indx++){
			individuals[index * CONNECTION_NUM + indx] = crossVec[indx];
		}
	}
	
	fitnessVector[index] = s_fitVec[threadId];
	__syncthreads();
	findMinFitness(fitnessVector,minFitness);

}


#endif // #ifndef _CPP_INTEGRATION_KERNEL_H_
